-
Notifications
You must be signed in to change notification settings - Fork 317
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Apply various fixes for new Sidebar/Header layout #6806
Conversation
@@ -141,6 +141,8 @@ rules: | |||
react/forbid-foreign-prop-types: off | |||
# Prevent undefined components. | |||
react/jsx-no-undef: warn | |||
# Allow arrow functions as props | |||
react/jsx-no-bind: off |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it's not common anymore to completely disallow arrow functions as props. There are situations where it's fine to use arrow functions, mainly for very simple one-off functions. We should still avoid them for complex functions that should rather be memoized.
@@ -151,7 +151,7 @@ const ClientsTable = () => { | |||
}), | |||
render: details => ( | |||
<ButtonGroup align="end"> | |||
<Button message={sharedMessages.restore} onClick={details.restore} /> | |||
<Button message={sharedMessages.restore} onClick={details.restore} secondary /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change has to do with a change of how the button works. I believe it's best to always explicitly pass the button style (primary
, secondary
, naked
) and apply no styling at all when no style prop is set, instead of relying on unstyled
or raw
props.
@@ -18,7 +18,7 @@ import classnames from 'classnames' | |||
|
|||
import authRoutes from '@account/constants/auth-routes' | |||
|
|||
import sidebarStyle from '@ttn-lw/components/navigation/side/side.styl' | |||
import sidebarStyle from '@ttn-lw/components/sidebar/side-menu/side.styl' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've moved the navigation/side
into the sidebar component. I believe this is the only place we should ever use this navigation list in. There are currently some areas where we use it outside of the sidebar (I believe in the Account app), but we will address this later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, also update the path in the side-menu story (pkg/webui/console/containers/side-bar/story.js
)
// Without secondary or primary style, | ||
// the button should not apply any styling. | ||
// This is to cater for special situations | ||
// where the button is used as a container. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my other comment, this way of styling also avoids a lot of repetition and style overlaps in the button component.
position: relative | ||
display: inline-flex | ||
transition: 80ms all ease-in-out | ||
border-radius: $br.m |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per design, the border radius for buttons is 7px (not 10.5).
const { brandLogo, className, children, profilePicture, ...rest } = props | ||
|
||
const handleClickOutside = useCallback(e => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was quite some logic duplication in here with regards to show/hiding the dropdown. I've refactored this to use the existing logic of the dropdown component.
position: relative | ||
height: 2.5rem | ||
|
||
&-curtain | ||
position: absolute | ||
overflow: hidden | ||
border-radius: $br.l | ||
width: 2.5rem | ||
transition: 0.3s 0s all cubic-bezier(0.770, 0.000, 0.175, 1.000) | ||
top: 0 | ||
left: 0 | ||
z-index: $zi.slight | ||
|
||
&:hover | ||
transition: 0.3s 0.2s all cubic-bezier(0.770, 0.000, 0.175, 1.000) | ||
width: 100% | ||
|
||
// Reveal the button label. | ||
button span:last-child | ||
opacity: 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fixes the jagged motion in the transition.
@@ -13,7 +13,7 @@ | |||
// limitations under the License. | |||
|
|||
import React from 'react' | |||
import { NavLink } from 'react-router-dom' | |||
import { Link } from 'react-router-dom' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for NavLink here
@@ -43,6 +44,13 @@ const MenuLink = ({ icon, title, path, onClick, exact, disabled }) => { | |||
<NavLink to={path} className={className} end={exact} onClick={onClick}> | |||
{icon && <Icon icon={icon} className={classnames(style.icon)} />}{' '} | |||
{!isMinimized && <Message content={title} />} | |||
{isMinimized && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The regular items should also show the flyout on hover, when the sidebar is collapsed.
@@ -12,18 +12,21 @@ | |||
// See the License for the specific language governing permissions and | |||
// limitations under the License. | |||
|
|||
.container |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of sticking the sidebar to the top, I've adjusted the layout to stay 100% always and then making the main
scrollable instead. This makes the layout simpler and avoids weird edge cases with sticky/fixed
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The header is now broken in account:
Check the render method of `Header`.
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
pkg/webui/console/containers/side-bar/navigation/app-list-side-navigation.js
Outdated
Show resolved
Hide resolved
&-support-dropdown | ||
right: -79px !important | ||
|
||
&-dropdown | ||
width: 18.2rem |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll fix this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After moving the navigation and separating this, when selecting uplink and then minimizing, it is not not possible to see which section is active. I tried to quickly understand why, but nothing major seemed to have changed.
@@ -18,7 +18,7 @@ import classnames from 'classnames' | |||
|
|||
import authRoutes from '@account/constants/auth-routes' | |||
|
|||
import sidebarStyle from '@ttn-lw/components/navigation/side/side.styl' | |||
import sidebarStyle from '@ttn-lw/components/sidebar/side-menu/side.styl' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, also update the path in the side-menu story (pkg/webui/console/containers/side-bar/story.js
)
} | ||
|
||
return ( | ||
<span {...componentProps}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assigning the component props to the span would result in secondary
being set and interpreted as HTML attribute.
@@ -52,9 +51,7 @@ const PortalledBreadcrumbs = ({ className, ...rest }) => { | |||
nodes.push( | |||
ReactDom.createPortal( | |||
<div className={classnames(className, style.breadcrumbsContainer)}> | |||
<Container> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the earlier layout, the breadcrumb container was embedded into the grid layout. This is now not the case anymore and it can be rendered as it. Otherwise it will render an additional padding that is not according to the screen design.
reset-button() | ||
position: relative | ||
display: inline-flex | ||
transition: 0.2s all ease-in-out |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting a transition on all
will lead to unwanted transitions on properties such as margin, padding, font-size etc.
|
||
const dataProps = useMemo(() => filterDataProps(rest), [rest]) | ||
|
||
const handleClickOutside = useCallback( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've outsourced the entire toggling logic of the dropdown into it's own component <Dropdown.Attached attachedRef={refOfButton} />
Reasons:
- Recurring logic that would otherwise need to be rewritten over and over (especially error prone due to the many edge-cases of dropdown toggling [trigger method, outside clicking, toggling, positioning)
- To easily enable dropdowns that are not rendered within the triggering button
/> | ||
)} | ||
<Dropdown className={classnames(dropdownClassName)} open={expanded}> | ||
{dropdownItems} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Notice that this previous implementation leads to <button />
's being rendered within a <button />
which is not HTML compliant and results in a warning and various accessibility issues.
|
||
const Sidebar = ({ isDrawerOpen }) => { | ||
const viewportWidth = getViewportWidth() | ||
const isMobile = viewportWidth <= LAYOUT.BREAKPOINTS.M |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we were talking about this before but the issue with a solution is that this only calculates once during render. However, this would not update if the screen size changes in between renders. For example, if you render in mobile screen size and then resize the browser window to desktop, the sidebar will still think it is isMobile
until it renders again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally speaking, using such props like isMobile
is typically unnecessary because most of the things that such a prop is used for can be solved by using media-queries instead. In this particular case, I've decided to leave it though since it enables to render tooltip dropdowns only when necessary (instead of hiding them via media-queries but still running mouse-in/out hooks).
'd-flex pos-fixed direction-column j-between gap-cs-m bg-tts-primary-050', | ||
'd-flex direction-column j-between gap-cs-m bg-tts-primary-050', | ||
{ | ||
[style.sidebarMinimized]: isMinimized, | ||
[style.sidebarOpen]: isMobile && isDrawerOpen, | ||
'p-cs-s': !isMinimized, | ||
'p-vert-cs-m': isMinimized, | ||
[style.sidebarOpen]: isDrawerOpen, | ||
'p-cs-m': !isMinimized, | ||
'p-vert-cs-s': isMinimized, | ||
'p-sides-cs-xs': isMinimized, | ||
}, | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still not optimal and quite confusing. All of this should rather be just done using plain CSS and media queries.
<SideFooter /> | ||
</SidebarContext.Provider> | ||
</div> | ||
<div className={style.sidebarBackdrop} onClick={onDrawerCloseClick} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the backdrop was missing in the earlier implementation. There was only a box-shadow, which however was not according to the screen design.
className="mt-cs-xs mb-cs-l" | ||
path={`/applications`} | ||
path={`/applications/${appId}`} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This had to be refactored throughout because for some reason after the refactor, the link would be rendered as applications/applications/app-id
.
Must've something to do with how react router determines the current route by calculating all <Route />
's up the render hierarchy.
@@ -361,7 +361,7 @@ transition-color() | |||
|
|||
sidebar-transition($properties) | |||
transition-timing-function: cubic-bezier(.18,.71,.3,.99) | |||
transition-duration: 330ms | |||
transition-duration: 0ms |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be streamlined and fixed eventually.
513c7bc
to
26e507c
Compare
26e507c
to
686a6e5
Compare
|
||
const Sidebar = ({ isDrawerOpen }) => { | ||
const viewportWidth = getViewportWidth() | ||
const isMobile = viewportWidth <= LAYOUT.BREAKPOINTS.M |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally speaking, using such props like isMobile
is typically unnecessary because most of the things that such a prop is used for can be solved by using media-queries instead. In this particular case, I've decided to leave it though since it enables to render tooltip dropdowns only when necessary (instead of hiding them via media-queries but still running mouse-in/out hooks).
if (!app) { | ||
return null | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before this, there were proptype warnings in the console for initial renders, when the app was not yet available.
Summary
This PR adds various functionality, implementation and styling fixes to the Sidebar/Header scaffold.
Changes
Notes for Reviewers
I've left many comments on the diff to explain various changes. @ryaplots @PavelJankoski please observe the changes corresponding to your components.
Checklist
README.md
for the chosen target branch.CHANGELOG.md
.CONTRIBUTING.md
, there are no fixup commits left.